<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Highscore - Boost C++ 库 - 智能指针</title>
<link rel="stylesheet" href="css/highscore.css" type="text/css">
<link rev="made" href="mailto:boris@highscore.de">
<link rel="home" href="frontpage.html" title="Boost C++ 库">
<link rel="up" href="frontpage.html" title="Boost C++ 库">
<link rel="prev" href="introduction.html" title="第 1 章 简介">
<link rel="next" href="functionobjects.html" title="第 3 章 函数对象">
<link rel="chapter" href="introduction.html" title="第 1 章 简介">
<link rel="chapter" href="smartpointers.html" title="第 2 章 智能指针">
<link rel="chapter" href="functionobjects.html" title="第 3 章 函数对象">
<link rel="chapter" href="eventhandling.html" title="第 4 章 事件处理">
<link rel="chapter" href="asio.html" title="第 5 章 异步输入输出">
<link rel="chapter" href="asio.html" title="第 6 章 异步输入输出">
<link rel="chapter" href="asio.html" title="第 7 章 异步输入输出">
<link rel="chapter" href="interprocesscommunication.html" title="第 8 章 进程间通讯">
<link rel="chapter" href="filesystem.html" title="第 9 章 文件系统">
<link rel="chapter" href="castoperators.html" title="第 10 章 类型转换操作符">
<link rel="chapter" href="castoperators.html" title="第 11 章 类型转换操作符">
<link rel="chapter" href="castoperators.html" title="第 12 章 类型转换操作符">
<link rel="chapter" href="castoperators.html" title="第 13 章 类型转换操作符">
<link rel="chapter" href="castoperators.html" title="第 14 章 类型转换操作符">
<link rel="chapter" href="castoperators.html" title="第 15 章 类型转换操作符">
<link rel="chapter" href="castoperators.html" title="第 16 章 类型转换操作符">
<link rel="section" href="smartpointers.html#smartpointers_general" title="2.1. ﻿概述">
<link rel="section" href="smartpointers.html#smartpointers_raii" title="2.2. RAII">
<link rel="section" href="smartpointers.html#smartpointers_scoped_pointer" title="2.3. 作用域指针">
<link rel="section" href="smartpointers.html#smartpointers_scoped_array" title="2.4. 作用域数组">
<link rel="section" href="smartpointers.html#smartpointers_shared_pointer" title="2.5. 共享指针">
<link rel="section" href="smartpointers.html#smartpointers_shared_array" title="2.6. 共享数组">
<link rel="section" href="smartpointers.html#smartpointers_weak_pointer" title="2.7. 弱指针">
<link rel="section" href="smartpointers.html#smartpointers_intrusive_pointer" title="2.8. 介入式指针">
<link rel="section" href="smartpointers.html#smartpointers_pointer_container" title="2.9. 指针容器">
<link rel="section" href="smartpointers.html#smartpointers_exercises" title="2.10. 练习">
<meta http-equiv="pics-label" content='(pics-1.1 "http://www.icra.org/ratingsv02.html" l gen true for "http://www.highscore.de" r (nz 1 vz 1 lz 1 oz 1 cz 1) gen true for "http://highscore.de" r (nz 1 vz 1 lz 1 oz 1 cz 1))'>
<meta http-equiv="Content-Style-Type" content="text/css">
<meta http-equiv="Content-Script-Type" content="text/javascript">
<link href="http://www.highscore.de/favicon.ico" rel="shortcut icon" type="image/vnd.microsoft.icon">
</head>
<body>
<div lang="zh" class="docbook chapter" title="第 2 章 智能指针">
<p class="title">Boost C++ 库</p>
<script type="text/javascript">
          var titlepage = "导言";
        
      var titles = new Array(titlepage,
      
        "第 1 章 简介",
      
        "第 2 章 智能指针",
      
        "第 3 章 函数对象",
      
        "第 4 章 事件处理",
      
        "第 5 章 异步输入输出",
      
        "第 6 章 异步输入输出",
      
        "第 7 章 异步输入输出",
      
        "第 8 章 进程间通讯",
      
        "第 9 章 文件系统",
      
        "第 10 章 类型转换操作符",
      
        "第 11 章 类型转换操作符",
      
        "第 12 章 类型转换操作符",
      
        "第 13 章 类型转换操作符",
      
        "第 14 章 类型转换操作符",
      
        "第 15 章 类型转换操作符",
      
        "第 16 章 类型转换操作符",
      
      "");

      
          var titlehtml = "frontpage.html";
        
      var filenames = new Array(titlehtml,
      
        "introduction.html",
      
        "smartpointers.html",
      
        "functionobjects.html",
      
        "eventhandling.html",
      
        "asio.html",
      
        "asio.html",
      
        "asio.html",
      
        "interprocesscommunication.html",
      
        "filesystem.html",
      
        "castoperators.html",
      
        "castoperators.html",
      
        "castoperators.html",
      
        "castoperators.html",
      
        "castoperators.html",
      
        "castoperators.html",
      
        "castoperators.html",
      
      "");

      
      document.open();
      document.write('<form action="" class="toc">');
      document.write('<select size="1" onchange="location.href=options[selectedIndex].value">');
      for (var i = 0; i < titles.length && i < filenames.length; ++i) {
        if (titles[i] != "" && filenames[i] != "") {
          document.write('<option');
          document.write(' value="' + filenames[i] + '"');
          var expr = new RegExp('[/\]' + filenames[i] + '$');
          if (expr.test(location.href)) {
            document.write(' selected="selected"');
          }
          document.write('>' + titles[i] + '<\/option>');
        }
      }
      document.write('<\/select>');
      document.write('<\/form>');
      document.close();
      
    </script><noscript><p class="toc"><a href="toc.html">目录</a></p></noscript>
<hr class="hrhead">
<h1 class="title">
<a name="smartpointers"></a>第 2 章 智能指针</h1>
<hr>
<div class="toc">
<h3>目录</h3>
<ul>
<li><span class="sect1"><a href="smartpointers.html#smartpointers_general">2.1 ﻿概述</a></span></li>
<li><span class="sect1"><a href="smartpointers.html#smartpointers_raii">2.2 RAII</a></span></li>
<li><span class="sect1"><a href="smartpointers.html#smartpointers_scoped_pointer">2.3 作用域指针</a></span></li>
<li><span class="sect1"><a href="smartpointers.html#smartpointers_scoped_array">2.4 作用域数组</a></span></li>
<li><span class="sect1"><a href="smartpointers.html#smartpointers_shared_pointer">2.5 共享指针</a></span></li>
<li><span class="sect1"><a href="smartpointers.html#smartpointers_shared_array">2.6 共享数组</a></span></li>
<li><span class="sect1"><a href="smartpointers.html#smartpointers_weak_pointer">2.7 弱指针</a></span></li>
<li><span class="sect1"><a href="smartpointers.html#smartpointers_intrusive_pointer">2.8 介入式指针</a></span></li>
<li><span class="sect1"><a href="smartpointers.html#smartpointers_pointer_container">2.9 指针容器</a></span></li>
<li><span class="sect1"><a href="smartpointers.html#smartpointers_exercises">2.10 练习</a></span></li>
</ul>
</div>
<p class="license"><a href="http://creativecommons.org/licenses/by-nc-nd/3.0/de/deed.zh" rel="license" target="_top"><img src="img/88x31_cc_logo.gif" alt="" width="88" height="31"></a> 该书采用 <a href="http://creativecommons.org/licenses/by-nc-nd/3.0/de/deed.zh" rel="license" target="_top">Creative Commons License</a> 授权</p>
<hr>
<h2 class="title">
<a name="smartpointers_general"></a>2.1. ﻿概述</h2>
<div class="sect1">
<p>1998年修订的第一版C++标准只提供了一种智能指针： <code class="classname">std::auto_ptr</code> 。
    它基本上就像是个普通的指针： 通过地址来访问一个动态分配的对象。 <code class="classname">std::auto_ptr</code>
    之所以被看作是智能指针，是因为它会在析构的时候调用 <code class="code">delete</code> 操作符来自动释放所包含的对象。
    当然这要求在初始化的时候，传给它一个由 <code class="code">new</code> 操作符返回的对象的地址。 既然
    <code class="classname">std::auto_ptr</code> 的析构函数会调用 <code class="code">delete</code>
    操作符，它所包含的对象的内存会确保释放掉。 这是智能指针的一个优点。</p>
<p>当和异常联系起来时这就更加重要了：没有 <code class="classname">std::auto_ptr</code>
    这样的智能指针，每一个动态分配内存的函数都需要捕捉所有可能的异常，以确保在异常传递给函数的调用者之前将内存释放掉。 Boost C++ 库
    <a class="link" href="http://www.boost.org/libs/smart_ptr/">Smart
    Pointers</a> 提供了许多可以用在各种场合的智能指针。</p>
</div>
<hr>
<h2 class="title">
<a name="smartpointers_raii"></a>2.2. RAII</h2>
<div class="sect1">
<p>智能指针的原理基于一个常见的习语叫做 RAII ：资源申请即初始化。 智能指针只是这个习语的其中一例——当然是相当重要的一例。
    智能指针确保在任何情况下，动态分配的内存都能得到正确释放，从而将开发人员从这项任务中解放了出来。
    这包括程序因为异常而中断，原本用于释放内存的代码被跳过的场景。 用一个动态分配的对象的地址来初始化智能指针，在析构的时候释放内存，就确保了这一点。
    因为析构函数总是会被执行的，这样所包含的内存也将总是会被释放。</p>
<p>无论何时，一定得有第二条指令来释放之前另一条指令所分配的资源时，RAII 都是适用的。 许多的 C++
    应用程序都需要动态管理内存，因而智能指针是一种很重要的 RAII 类型。 不过 RAII 本身是适用于许多其它场景的。</p>
<pre class="programlisting">#include &lt;windows.h&gt; 

class windows_handle 
{ 
  public: 
    windows_handle(HANDLE h) 
      : handle_(h) 
    { 
    } 

    ~windows_handle() 
    { 
      CloseHandle(handle_); 
    } 

    HANDLE handle() const 
    { 
      return handle_; 
    } 

  private: 
    HANDLE handle_; 
}; 

int main() 
{ 
  windows_handle h(OpenProcess(PROCESS_SET_INFORMATION, FALSE, GetCurrentProcessId())); 
  SetPriorityClass(h.handle(), HIGH_PRIORITY_CLASS); 
} </pre>
<ul class="programlisting"><li><a class="programlisting" href="src/2.2.1/main.cpp">下载源代码</a></li></ul>
<p>上面的例子中定义了一个名为 <code class="classname">windows_handle</code> 的类，它的析构函数调用了
    <code class="function">CloseHandle()</code> 函数。 这是一个 Windows API 函数，因而这个程序只能在 Windows
    上运行。 在 Windows 上，许多资源在使用之前都要求打开。 这暗示着一旦资源不再使用之后就应该关闭。
    <code class="classname">windows_handle</code> 类的机制能确保这一点。</p>
<p><code class="classname">windows_handle</code> 类的实例以一个句柄来初始化。 Windows
    使用句柄来唯一的标识资源。 比如说，<code class="function">OpenProcess()</code> 函数返回一个
    <code class="type">HANDLE</code> 类型的句柄，通过该句柄可以访问当前系统中的进程。
    在示例代码中，访问的是进程自己——换句话说就是应用程序本身。</p>
<p>我们通过这个返回的句柄提升了进程的优先级，这样它就能从调度器那里获得更多的 CPU 时间。 这里只是用于演示目的，并没什么实际的效应。
    重要的一点是：通过 <code class="function">OpenProcess()</code> 打开的资源不需要显示的调用
    <code class="function">CloseHandle()</code> 来关闭。 当然，应用程序终止时资源也会随之关闭。 然而，在更加复杂的应用程序里，
    <code class="classname">windows_handle</code> 类确保当一个资源不再使用时就能正确的关闭。
    某个资源一旦离开了它的作用域——上例中 <var>h</var> 的作用域在 <code class="function">main()</code>
    函数的末尾——它的析构函数会被自动的调用，相应的资源也就释放掉了。</p>
</div>
<hr>
<h2 class="title">
<a name="smartpointers_scoped_pointer"></a>2.3. 作用域指针</h2>
<div class="sect1">
<p>一个作用域指针独占一个动态分配的对象。 对应的类名为
    <code class="classname">boost::scoped_ptr</code>，它的定义在 <code class="filename">boost/scoped_ptr.hpp</code> 中。 不像
    <code class="classname">std::auto_ptr</code>，一个作用域指针不能传递它所包含的对象的所有权到另一个作用域指针。
    一旦用一个地址来初始化，这个动态分配的对象将在析构阶段释放。</p>
<p>因为一个作用域指针只是简单保存和独占一个内存地址，所以 <code class="classname">boost::scoped_ptr</code>
    的实现就要比 <code class="classname">std::auto_ptr</code> 简单。 在不需要所有权传递的时候应该优先使用
    <code class="classname">boost::scoped_ptr</code> 。 在这些情况下，比起
    <code class="classname">std::auto_ptr</code> 它是一个更好的选择，因为可以避免不经意间的所有权传递。</p>
<pre class="programlisting">#include &lt;boost/scoped_ptr.hpp&gt; 

int main() 
{ 
  boost::scoped_ptr&lt;int&gt; i(new int); 
  *i = 1; 
  *i.get() = 2; 
  i.reset(new int); 
} </pre>
<ul class="programlisting"><li><a class="programlisting" href="src/2.3.1/main.cpp">下载源代码</a></li></ul>
<p>一经初始化，智能指针 <code class="classname">boost::scoped_ptr</code>
    所包含的对象，可以通过类似于普通指针的接口来访问。 这是因为重载了相关的操作符
    <code class="methodname">operator*()</code>，<code class="methodname">operator-&gt;()</code>
    和 <code class="methodname">operator bool()</code> 。 此外，还有
    <code class="methodname">get()</code> 和 <code class="methodname">reset()</code> 方法。
    前者返回所含对象的地址，后者用一个新的对象来重新初始化智能指针。 在这种情况下，新创建的对象赋值之前会先自动释放所包含的对象。</p>
<p><code class="classname">boost::scoped_ptr</code> 的析构函数中使用
    <code class="code">delete</code> 操作符来释放所包含的对象。 这对
    <code class="classname">boost::scoped_ptr</code> 所包含的类型加上了一条重要的限制。
    <code class="classname">boost::scoped_ptr</code> 不能用动态分配的数组来做初始化，因为这需要调用
    <code class="code">delete[]</code> 来释放。 在这种情况下，可以使用下面将要介绍的
    <code class="classname">boost:scoped_array</code> 类。</p>
</div>
<hr>
<h2 class="title">
<a name="smartpointers_scoped_array"></a>2.4. 作用域数组</h2>
<div class="sect1">
<p>作用域数组的使用方式与作用域指针相似。 关键不同在于，作用域数组的析构函数使用 <code class="code">delete[]</code>
    操作符来释放所包含的对象。 因为该操作符只能用于数组对象，所以作用域数组必须通过动态分配的数组来初始化。</p>
<p>对应的作用域数组类名为 <code class="classname">boost::scoped_array</code>，它的定义在
    <code class="filename">boost/scoped_array.hpp</code> 里。</p>
<pre class="programlisting">#include &lt;boost/scoped_array.hpp&gt; 

int main() 
{ 
  boost::scoped_array&lt;int&gt; i(new int[2]); 
  *i.get() = 1; 
  i[1] = 2; 
  i.reset(new int[3]); 
} </pre>
<ul class="programlisting"><li><a class="programlisting" href="src/2.4.1/main.cpp">下载源代码</a></li></ul>
<p><code class="classname">boost:scoped_array</code> 类重载了操作符
    <code class="methodname">operator[]()</code> 和 <code class="methodname">operator
    bool()</code>。 可以通过 <code class="methodname">operator[]()</code>
    操作符访问数组中特定的元素，于是 <code class="classname">boost::scoped_array</code>
    类型对象的行为就酷似它所含的数组。</p>
<p>正如 <code class="classname">boost::scoped_ptr</code> 那样,
    <code class="classname">boost:scoped_array</code> 也提供了
    <code class="methodname">get()</code> 和 <code class="methodname">reset()</code>
    方法，用来返回和重新初始化所含对象的地址。</p>
</div>
<hr>
<h2 class="title">
<a name="smartpointers_shared_pointer"></a>2.5. 共享指针</h2>
<div class="sect1">
<p>这是使用率最高的智能指针，但是 C++ 标准的第一版中缺少这种指针。 它已经作为技术报告1（TR 1）的一部分被添加到标准里了。
    如果开发环境支持的话，可以使用 <code class="filename">memory</code> 中定义的
    <code class="classname">std::shared_ptr</code>。 在 Boost C++ 库里，这个智能指针命名为
    <code class="classname">boost::shared_ptr</code>，定义在 <code class="filename">boost/shared_ptr.hpp</code> 里。</p>
<p>智能指针 <code class="classname">boost::shared_ptr</code> 基本上类似于
    <code class="classname">boost::scoped_ptr</code>。 关键不同之处在于
    <code class="classname">boost::shared_ptr</code> 不一定要独占一个对象。 它可以和其他
    <code class="classname">boost::shared_ptr</code> 类型的智能指针共享所有权。
    在这种情况下，当引用对象的最后一个智能指针销毁后，对象才会被释放。</p>
<p>因为所有权可以在 <code class="classname">boost::shared_ptr</code>
    之间共享，任何一个共享指针都可以被复制，这跟 <code class="classname">boost::scoped_ptr</code> 是不同的。
    这样就可以在标准容器里存储智能指针了——你不能在标准容器中存储
    <code class="classname">std::auto_ptr</code>，因为它们在拷贝的时候传递了所有权。</p>
<pre class="programlisting">#include &lt;boost/shared_ptr.hpp&gt; 
#include &lt;vector&gt; 

int main() 
{ 
  std::vector&lt;boost::shared_ptr&lt;int&gt; &gt; v; 
  v.push_back(boost::shared_ptr&lt;int&gt;(new int(1))); 
  v.push_back(boost::shared_ptr&lt;int&gt;(new int(2))); 
} </pre>
<ul class="programlisting"><li><a class="programlisting" href="src/2.5.1/main.cpp">下载源代码</a></li></ul>
<p>多亏了有
    <code class="classname">boost::shared_ptr</code>，我们才能像上例中展示的那样，在标准容器中安全的使用动态分配的对象。
    因为 <code class="classname">boost::shared_ptr</code>
    能够共享它所含对象的所有权，所以保存在容器中的拷贝（包括容器在需要时额外创建的拷贝）都是和原件相同的。如前所述，<code class="classname">std::auto_ptr</code>做不到这一点，所以绝对不应该在容器中保存它们。</p>
<p>类似于 <code class="classname">boost::scoped_ptr</code>，
    <code class="classname">boost::shared_ptr</code>
    类重载了以下这些操作符：<code class="methodname">operator*()</code>，<code class="methodname">operator-&gt;()</code>
    和 <code class="methodname">operator bool()</code>。另外还有 <code class="methodname">get()</code>
    和 <code class="methodname">reset()</code> 函数来获取和重新初始化所包含的对象的地址。</p>
<pre class="programlisting">#include &lt;boost/shared_ptr.hpp&gt; 

int main() 
{ 
  boost::shared_ptr&lt;int&gt; i1(new int(1)); 
  boost::shared_ptr&lt;int&gt; i2(i1); 
  i1.reset(new int(2)); 
} </pre>
<ul class="programlisting"><li><a class="programlisting" href="src/2.5.2/main.cpp">下载源代码</a></li></ul>
<p>本例中定义了2个共享指针 <var>i1</var> 和 <var>i2</var>，它们都引用到同一个
    <code class="type">int</code> 类型的对象。<var>i1</var> 通过 <code class="code">new</code>
    操作符返回的地址显示的初始化，<var>i2</var> 通过 <var>i1</var> 拷贝构造而来。
    <var>i1</var> 接着调用
    <code class="methodname">reset()</code>，它所包含的整数的地址被重新初始化。不过它之前所包含的对象并没有被释放，因为
    <var>i2</var> 仍然引用着它。 智能指针
    <code class="classname">boost::shared_ptr</code>
    记录了有多少个共享指针在引用同一个对象，只有在最后一个共享指针销毁时才会释放这个对象。</p>
<p>默认情况下，<code class="classname">boost::shared_ptr</code> 使用
    <code class="code">delete</code> 操作符来销毁所含的对象。
    然而，具体通过什么方法来销毁，是可以指定的，就像下面的例子里所展示的：</p>
<pre class="programlisting">#include &lt;boost/shared_ptr.hpp&gt; 
#include &lt;windows.h&gt; 

int main() 
{ 
  boost::shared_ptr&lt;void&gt; h(OpenProcess(PROCESS_SET_INFORMATION, FALSE, GetCurrentProcessId()), CloseHandle); 
  SetPriorityClass(h.get(), HIGH_PRIORITY_CLASS); 
} </pre>
<ul class="programlisting"><li><a class="programlisting" href="src/2.5.3/main.cpp">下载源代码</a></li></ul>
<p><code class="classname">boost::shared_ptr</code>
    的构造函数的第二个参数是一个普通函数或者函数对象，该参数用来销毁所含的对象。 在本例中，这个参数是 Windows API 函数
    <code class="function">CloseHandle()</code>。 当变量 <var>h</var>
    超出它的作用域时，调用的是这个函数而不是 <code class="code">delete</code> 操作符来销毁所含的对象。 为了避免编译错误，该函数只能带一个
    <code class="type">HANDLE</code> 类型的参数， <code class="function">CloseHandle()</code> 正好符合要求。</p>
<p>该例和本章稍早讲述 RAII 习语时所用的例子的运行是一样的。 然而，本例没有单独定义一个
    <code class="classname">windows_handle</code> 类，而是利用了
    <code class="classname">boost::shared_ptr</code>
    的特性，给它的构造函数传递一个方法，这个方法会在共享指针超出它的作用域时自动调用。</p>
</div>
<hr>
<h2 class="title">
<a name="smartpointers_shared_array"></a>2.6. 共享数组</h2>
<div class="sect1">
<p>共享数组的行为类似于共享指针。 关键不同在于共享数组在析构时，默认使用 <code class="code">delete[]</code>
    操作符来释放所含的对象。 因为这个操作符只能用于数组对象，共享数组必须通过动态分配的数组的地址来初始化。</p>
<p>共享数组对应的类型是 <code class="classname">boost::shared_array</code>，它的定义在
    <code class="filename">boost/shared_array.hpp</code> 里。</p>
<pre class="programlisting">#include &lt;boost/shared_array.hpp&gt; 
#include &lt;iostream&gt; 

int main() 
{ 
  boost::shared_array&lt;int&gt; i1(new int[2]); 
  boost::shared_array&lt;int&gt; i2(i1); 
  i1[0] = 1; 
  std::cout &lt;&lt; i2[0] &lt;&lt; std::endl; 
} </pre>
<ul class="programlisting"><li><a class="programlisting" href="src/2.6.1/main.cpp">下载源代码</a></li></ul>
<p>就像共享指针那样，所含对象的所有权可以跟其他共享数组来共享。 这个例子中定义了2个变量 <var>i1</var> 和
    <var>i2</var>，它们引用到同一个动态分配的数组。<var>i1</var> 通过
    <code class="methodname">operator[]()</code> 操作符保存了一个整数1——这个整数可以被
    <var>i2</var> 引用，比如打印到标准输出。</p>
<p>和本章中所有的智能指针一样，<code class="classname">boost::shared_array</code> 也同样提供了
    <code class="methodname">get()</code> 和 <code class="methodname">reset()</code> 方法。 另外还重载了
    <code class="methodname">operator bool()</code>。</p>
</div>
<hr>
<h2 class="title">
<a name="smartpointers_weak_pointer"></a>2.7. 弱指针</h2>
<div class="sect1">
<p>到目前为止介绍的各种智能指针都能在不同的场合下独立使用。 相反，弱指针只有在配合共享指针一起使用时才有意义。 弱指针
    <code class="classname">boost::weak_ptr</code> 的定义在 <code class="filename">boost/weak_ptr.hpp</code> 里。</p>
<pre class="programlisting">#include &lt;windows.h&gt; 
#include &lt;boost/shared_ptr.hpp&gt; 
#include &lt;boost/weak_ptr.hpp&gt; 
#include &lt;iostream&gt; 

DWORD WINAPI reset(LPVOID p) 
{ 
  boost::shared_ptr&lt;int&gt; *sh = static_cast&lt;boost::shared_ptr&lt;int&gt;*&gt;(p); 
  sh-&gt;reset(); 
  return 0; 
} 

DWORD WINAPI print(LPVOID p) 
{ 
  boost::weak_ptr&lt;int&gt; *w = static_cast&lt;boost::weak_ptr&lt;int&gt;*&gt;(p); 
  boost::shared_ptr&lt;int&gt; sh = w-&gt;lock(); 
  if (sh) 
    std::cout &lt;&lt; *sh &lt;&lt; std::endl; 
  return 0; 
} 

int main() 
{ 
  boost::shared_ptr&lt;int&gt; sh(new int(99)); 
  boost::weak_ptr&lt;int&gt; w(sh); 
  HANDLE threads[2]; 
  threads[0] = CreateThread(0, 0, reset, &amp;sh, 0, 0); 
  threads[1] = CreateThread(0, 0, print, &amp;w, 0, 0); 
  WaitForMultipleObjects(2, threads, TRUE, INFINITE); 
} </pre>
<ul class="programlisting"><li><a class="programlisting" href="src/2.7.1/main.cpp">下载源代码</a></li></ul>
<p><code class="classname">boost::weak_ptr</code> 必定总是通过
    <code class="classname">boost::shared_ptr</code> 来初始化的。一旦初始化之后，它基本上只提供一个有用的方法:
    <code class="methodname">lock()</code>。此方法返回的<code class="classname">boost::shared_ptr</code>
    与用来初始化弱指针的共享指针共享所有权。 如果这个共享指针不含有任何对象，返回的共享指针也将是空的。</p>
<p>当函数需要一个由共享指针所管理的对象，而这个对象的生存期又不依赖于这个函数时，就可以使用弱指针。
    只要程序中还有一个共享指针掌管着这个对象，函数就可以使用该对象。 如果共享指针复位了，就算函数里能得到一个共享指针，对象也不存在了。</p>
<p>上例的 <code class="function">main()</code> 函数中，通过 Windows API 创建了2个线程。 于是乎，该例只能在
    Windows 平台上编译运行。</p>
<p>第一个线程函数 <code class="function">reset()</code> 的参数是一个共享指针的地址。 第二个线程函数
    <code class="function">print()</code> 的参数是一个弱指针的地址。 这个弱指针是之前通过共享指针初始化的。</p>
<p>一旦程序启动之后，<code class="function">reset()</code> 和 <code class="function">print()</code>
    就都开始执行了。 不过执行顺序是不确定的。 这就导致了一个潜在的问题：<code class="function">reset()</code>
    线程在销毁对象的时候<code class="function">print()</code> 线程可能正在访问它。</p>
<p>通过调用弱指针的 <code class="methodname">lock()</code> 函数可以解决这个问题：如果对象存在，那么
    <code class="methodname">lock()</code>
    函数返回的共享指针指向这个合法的对象。否则，返回的共享指针被设置为0，这等价于标准的null指针。</p>
<p>弱指针本身对于对象的生存期没有任何影响。 <code class="methodname">lock()</code>
    返回一个共享指针，<code class="function">print()</code> 函数就可以安全的访问对象了。
    这就保证了——即使另一个线程要释放对象——由于我们有返回的共享指针，对象依然存在。</p>
</div>
<hr>
<h2 class="title">
<a name="smartpointers_intrusive_pointer"></a>2.8. 介入式指针</h2>
<div class="sect1">
<p>大体上，介入式指针的工作方式和共享指针完全一样。 <code class="classname">boost::shared_ptr</code>
    在内部记录着引用到某个对象的共享指针的数量，可是对介入式指针来说，程序员就得自己来做记录。
    对于框架对象来说这就特别有用，因为它们记录着自身被引用的次数。</p>
<p>介入式指针 <code class="classname">boost::intrusive_ptr</code> 定义在 <code class="filename">boost/intrusive_ptr.hpp</code> 里。</p>
<pre class="programlisting">#include &lt;boost/intrusive_ptr.hpp&gt; 
#include &lt;atlbase.h&gt; 
#include &lt;iostream&gt; 

void intrusive_ptr_add_ref(IDispatch *p) 
{ 
  p-&gt;AddRef(); 
} 

void intrusive_ptr_release(IDispatch *p) 
{ 
  p-&gt;Release(); 
} 

void check_windows_folder() 
{ 
  CLSID clsid; 
  CLSIDFromProgID(CComBSTR("Scripting.FileSystemObject"), &amp;clsid); 
  void *p; 
  CoCreateInstance(clsid, 0, CLSCTX_INPROC_SERVER, __uuidof(IDispatch), &amp;p); 
  boost::intrusive_ptr&lt;IDispatch&gt; disp(static_cast&lt;IDispatch*&gt;(p)); 
  CComDispatchDriver dd(disp.get()); 
  CComVariant arg("C:\\Windows"); 
  CComVariant ret(false); 
  dd.Invoke1(CComBSTR("FolderExists"), &amp;arg, &amp;ret); 
  std::cout &lt;&lt; (ret.boolVal != 0) &lt;&lt; std::endl; 
} 

void main() 
{ 
  CoInitialize(0); 
  check_windows_folder(); 
  CoUninitialize(); 
} </pre>
<ul class="programlisting"><li><a class="programlisting" href="src/2.8.1/main.cpp">下载源代码</a></li></ul>
<p>上面的例子中使用了 COM（组件对象模型）提供的函数，于是乎只能在 Windows 平台上编译运行。 COM 对象是使用
    <code class="classname">boost::intrusive_ptr</code> 的绝佳范例，因为 COM
    对象需要记录当前有多少指针引用着它。 通过调用 <code class="methodname">AddRef()</code> 和
    <code class="methodname">Release()</code> 函数，内部的引用计数分别增 1 或者减 1。当引用计数为 0 时，COM
    对象自动销毁。</p>
<p>在 <code class="function">intrusive_ptr_add_ref()</code> 和
    <code class="function">intrusive_ptr_release()</code> 内部调用
    <code class="methodname">AddRef()</code> 和 <code class="methodname">Release()</code>
    这两个函数，来增加或减少相应 COM 对象的引用计数。 这个例子中用到的 COM 对象名为 'FileSystemObject'，在 Windows
    上它是默认可用的。通过这个对象可以访问底层的文件系统，比如检查一个给定的目录是否存在。 在上例中，我们检查 <code class="filename">C:\Windows</code> 目录是否存在。 具体它在内部是怎么实现的，跟
    <code class="classname">boost::intrusive_ptr</code> 的功能无关，完全取决于 COM。 关键点在于一旦介入式指针
    <var>disp</var>
    离开了它的作用域——<code class="function">check_windows_folder()</code> 函数的末尾，函数
    <code class="function">intrusive_ptr_release()</code> 将会被自动调用。 这将减少 COM 对象
    'FileSystemObject' 的内部引用计数到0，于是该对象就销毁了。</p>
</div>
<hr>
<h2 class="title">
<a name="smartpointers_pointer_container"></a>2.9. 指针容器</h2>
<div class="sect1">
<p>在你见过 Boost C++
    库的各种智能指针之后，应该能够编写安全的代码，来使用动态分配的对象和数组。多数时候，这些对象要存储在容器里——如上所述——使用
    <code class="classname">boost::shared_ptr</code> 和
    <code class="classname">boost::shared_array</code> 这就相当简单了。</p>
<pre class="programlisting">#include &lt;boost/shared_ptr.hpp&gt; 
#include &lt;vector&gt; 

int main() 
{ 
  std::vector&lt;boost::shared_ptr&lt;int&gt; &gt; v; 
  v.push_back(boost::shared_ptr&lt;int&gt;(new int(1))); 
  v.push_back(boost::shared_ptr&lt;int&gt;(new int(2))); 
} </pre>
<ul class="programlisting"><li><a class="programlisting" href="src/2.9.1/main.cpp">下载源代码</a></li></ul>
<p>上面例子中的代码当然是正确的，智能指针确实可以这样用，然而因为某些原因，实际情况中并不这么用。 第一，反复声明
    <code class="classname">boost::shared_ptr</code> 需要更多的输入。 其次，将
    <code class="classname">boost::shared_ptr</code>
    拷进，拷出，或者在容器内部做拷贝，需要频繁的增加或者减少内部引用计数，这肯定效率不高。 由于这些原因，Boost C++ 库提供了 <a class="link" href="http://www.boost.org/libs/ptr_container/"> 指针容器</a>
    专门用来管理动态分配的对象。</p>
<pre class="programlisting">#include &lt;boost/ptr_container/ptr_vector.hpp&gt; 

int main() 
{ 
  boost::ptr_vector&lt;int&gt; v; 
  v.push_back(new int(1)); 
  v.push_back(new int(2)); 
} </pre>
<ul class="programlisting"><li><a class="programlisting" href="src/2.9.2/main.cpp">下载源代码</a></li></ul>
<p><code class="classname">boost::ptr_vector</code> 类的定义在 <code class="filename">boost/ptr_container/ptr_vector.hpp</code>
    里，它跟前一个例子中用 <code class="classname">boost::shared_ptr</code> 模板参数来初始化的容器具有相同的工作方式。
    <code class="classname">boost::ptr_vector</code> 专门用于动态分配的对象，它使用起来更容易也更高效。
    <code class="classname">boost::ptr_vector</code> 独占它所包含的对象，因而容器之外的共享指针不能共享所有权，这跟
    <code class="code">std::vector&lt;boost::shared_ptr&lt;int&gt; &gt;</code> 相反。</p>
<p>除了 <code class="classname">boost::ptr_vector</code>
    之外，专门用于管理动态分配对象的容器还包括：<code class="classname">boost::ptr_deque</code>，
    <code class="classname">boost::ptr_list</code>，
    <code class="classname">boost::ptr_set</code>，
    <code class="classname">boost::ptr_map</code>，
    <code class="classname">boost::ptr_unordered_set</code> 和
    <code class="classname">boost::ptr_unordered_map</code>。这些容器等价于C++标准里提供的那些。最后两个容器对应于<code class="classname">std::unordered_set</code>
    和 <code class="classname">std::unordered_map</code>，它们作为技术报告1的一部分加入 C++ 标准。 如果所使用的
    C++ 标准实现不支持技术报告1的话，还可以使用 Boost C++ 库里实现的
    <code class="classname">boost::unordered_set</code> 和
    <code class="classname">boost::unordered_map</code>。</p>
</div>
<hr>
<h2 class="title">
<a name="smartpointers_exercises"></a>2.10. 练习</h2>
<div class="sect1">
<p class="solution">
              You can buy 
              <a target="_top" href="http://en.highscore.de/shop/index.php?p=boost-solution">solutions to all exercises</a>
              in this book as a ZIP file. 
            </p>
<ol>
<li class="listitem">
<p>使用适当的智能指针优化下面的程序：</p>
<pre class="programlisting">#include &lt;iostream&gt; 
#include &lt;cstring&gt; 

char *get(const char *s) 
{ 
  int size = std::strlen(s); 
  char *text = new char[size + 1]; 
  std::strncpy(text, s, size + 1); 
  return text; 
} 

void print(char *text) 
{ 
  std::cout &lt;&lt; text &lt;&lt; std::endl; 
} 

int main(int argc, char *argv[]) 
{ 
  if (argc &lt; 2) 
  { 
    std::cerr &lt;&lt; argv[0] &lt;&lt; " &lt;data&gt;" &lt;&lt; std::endl; 
    return 1; 
  } 

  char *text = get(argv[1]); 
  print(text); 
  delete[] text; 
} </pre>
<ul class="programlisting"><li><a class="programlisting" href="src/2.10.1/main.cpp">下载源代码</a></li></ul>
</li>
<li class="listitem">
<p>优化下面的程序：</p>
<pre class="programlisting">#include &lt;vector&gt; 

template &lt;typename T&gt; 
T *create() 
{ 
  return new T; 
} 

int main() 
{ 
  std::vector&lt;int*&gt; v; 
  v.push_back(create&lt;int&gt;()); 
} </pre>
<ul class="programlisting"><li><a class="programlisting" href="src/2.10.2/main.cpp">下载源代码</a></li></ul>
</li>
</ol>
</div>
</div>
<hr class="hrfoot">
<p class="copyright">版权 © 2008-2010 
        <a class="link" href="mailto:boris@highscore.de">Boris Schäling</a>
      </p>
</body>
</html>
